package com.iris.thread.produceConsume;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 项目: thinking
 * 包名: com.iris.thread.produceConsume
 * 作者: victor
 * 日期: 2016年11月1日
 * 说明: ReentrantLockProduceConsume
 * 同步代码与同步代码块可以实现多线程的同步，JAVA并发框架提供另外了一个框架，它也能实现多线程的同步，即是Lock和Condition，Condition和Lock是配合在一起使用，从字面意思上看，Condition是条件锁，有了锁，为什么要引用条件锁呢？原因有两个：
     1.对一个共享资源有读和写的能力，如果读线程或写线程获取了Lock的权力，即有能力进入，但是如果里面没有内容，读也没有用，如果空间已满了，写也写不了，所有还得有条件去判断一下，是不是线程要等待了；
     2.提供一种多线程之间的通信机制，类似wait()和nofity()的原理。
 */
public class ReentrantLockProduceConsume {
	private List<String> list = new ArrayList<String>();
	
	private ReentrantLock lock = new ReentrantLock();
	private int maxCount=100;
	private int minCount=0;
	private Condition maxCondition = lock.newCondition();
	private Condition minCondition = lock.newCondition();
	public void produce(){
		lock.lock();
		String uuid="";
		try {
			if(list.size()>=maxCount){
				maxCondition.await();
			}
			uuid = UUID.randomUUID().toString();
			list.add(uuid);
			System.out.println(uuid+"======="+list.size()+"==="+Thread.currentThread().getName());
			minCondition.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}finally {
			lock.unlock();
		}
		
		
	}
	
	public void consume(){
		lock.lock();
		try {
			if(list.size()<=minCount){
				minCondition.await();
			}
			System.out.println(list.remove(0)+"======="+list.size()+"==="+Thread.currentThread().getName());
			maxCondition.signalAll();
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}finally {
			lock.unlock();
		}
	}
	
	public static void main(String[] args) {
		ReentrantLockProduceConsume pl = new ReentrantLockProduceConsume();
		Thread produce = new Thread(new ReentrantLockProduceRunnable(pl),"produce");
		Thread produce1 = new Thread(new ReentrantLockProduceRunnable(pl),"produce1");
		Thread consume = new Thread(new ReentrantLockConsumeRunnable(pl),"consume");
		Thread consume1 = new Thread(new ReentrantLockConsumeRunnable(pl),"consume1");
		produce.start();
		consume.start();
		produce1.start();
		consume1.start();
		
	}
}

class ReentrantLockProduceRunnable implements Runnable{
	private ReentrantLockProduceConsume pl;
	public ReentrantLockProduceRunnable(ReentrantLockProduceConsume pl){
		this.pl = pl;
	}
	public void run() {
		while(true){
			try {
				pl.produce();
//				Thread.sleep(100);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
}

class ReentrantLockConsumeRunnable implements Runnable{
	private ReentrantLockProduceConsume pl;
	public ReentrantLockConsumeRunnable(ReentrantLockProduceConsume pl){
		this.pl = pl;
	}
	public void run() {
		while(true){
			try {
				pl.consume();
//				Thread.sleep(1000);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
}

